home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pine / ttyin.c < prev    next >
C/C++ Source or Header  |  1997-02-24  |  67KB  |  2,480 lines

  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: ttyin.c,v 4.139 1996/07/09 23:10:55 mikes Exp $";
  3. #endif
  4. /*----------------------------------------------------------------------
  5.  
  6.             T H E    P I N E    M A I L   S Y S T E M
  7.  
  8.    Laurence Lundblade and Mike Seibel
  9.    Networks and Distributed Computing
  10.    Computing and Communications
  11.    University of Washington
  12.    Administration Builiding, AG-44
  13.    Seattle, Washington, 98195, USA
  14.    Internet: lgl@CAC.Washington.EDU
  15.              mikes@CAC.Washington.EDU
  16.  
  17.    Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  18.  
  19.  
  20.    Pine and Pico are registered trademarks of the University of Washington.
  21.    No commercial use of these trademarks may be made without prior written
  22.    permission of the University of Washington.
  23.  
  24.    Pine, Pico, and Pilot software and its included text are Copyright
  25.    1989-1996 by the University of Washington.
  26.  
  27.    The full text of our legal notices is contained in the file called
  28.    CPYRIGHT, included with this distribution.
  29.  
  30.  
  31.    Pine is in part based on The Elm Mail System:
  32.     ***********************************************************************
  33.     *  The Elm Mail System  -  Revision: 2.13                             *
  34.     *                                                                     *
  35.     *             Copyright (c) 1986, 1987 Dave Taylor              *
  36.     *             Copyright (c) 1988, 1989 USENET Community Trust   *
  37.     ***********************************************************************
  38.  
  39.  
  40.   ----------------------------------------------------------------------*/
  41.  
  42. /*======================================================================
  43.        ttyin.c
  44.        Things having to do with reading from the tty driver and keyboard
  45.           - initialize tty driver and reset tty driver
  46.           - read a character from terminal with keyboard escape seqence mapping
  47.           - initialize keyboard (keypad or such) and reset keyboard
  48.           - prompt user for a line of input
  49.           - read a command from keyboard with timeouts.
  50.  
  51.  ====*/
  52.  
  53.  
  54. /*
  55.  * Helpful definitions
  56.  */
  57. #define    RETURN_CH(X)    return(key_recorder((X), 0))
  58.  
  59.  
  60. #if    !(defined(DOS) || defined(OS2))
  61. /* Beginning of giant switch between UNIX and DOS input driver */
  62.  
  63. #include "headers.h"
  64.  
  65. /*
  66.  * Internal prototypes
  67.  */
  68. void line_paint PROTO((int, int *));
  69. int  process_config_input PROTO((int *));
  70. int  getchar_for_kbseq PROTO ((void));
  71. int  check_for_timeout PROTO((int));
  72. int  read_a_char PROTO((void));
  73. void read_bail PROTO((void));
  74.  
  75. #ifdef USE_POLL
  76. #include <stropts.h>
  77. #include <poll.h>
  78. #endif
  79.  
  80. #ifdef HAVE_TERMIOS
  81. struct termios _raw_tty, _original_tty;
  82. #else
  83. #ifdef HAVE_TERMIO
  84. static struct termio _raw_tty, _original_tty;
  85. #else /* HAVE_TERMIO */
  86. static struct sgttyb  _raw_tty,     _original_tty;
  87. static struct ltchars _raw_ltchars, _original_ltchars;
  88. static struct tchars  _raw_tchars,  _original_tchars;
  89. static int            _raw_lmode,   _original_lmode;
  90. #endif /* HAVE_TERMIO  */
  91. #endif /* HAVE_TERMIOS */
  92.  
  93. /*
  94.  * current raw state
  95.  */
  96. static short _inraw = 0;
  97.  
  98.  
  99. #define STDIN_FD    0
  100. #define STDOUT_FD    1
  101.  
  102. /*----------------------------------------------------------------------
  103.     Initialize the tty driver to do single char I/O and whatever else  (UNIX)
  104.  
  105.    Args:  struct pine
  106.  
  107.  Result: tty driver is put in raw mode so characters can be read one
  108.          at a time. Returns -1 if unsuccessful, 0 if successful.
  109.  
  110. Some file descriptor voodoo to allow for pipes across vforks. See 
  111. open_mailer for details.
  112.   ----------------------------------------------------------------------*/
  113. init_tty_driver(ps)
  114.      struct pine *ps;
  115. {
  116. #ifdef    MOUSE
  117.     if(F_ON(F_ENABLE_MOUSE, ps_global))
  118.       if(init_mouse())
  119.     kpinsert(&ps->kbesc, "\033[M", KEY_XTERM_MOUSE);
  120. #endif    /* MOUSE */
  121.  
  122.     /* turn off talk permission by default */
  123.     
  124.     if(F_ON(F_ALLOW_TALK, ps))
  125.       allow_talk(ps);
  126.     else
  127.       disallow_talk(ps);
  128.  
  129.     return(Raw(1));
  130. }
  131.  
  132.  
  133. /*----------------------------------------------------------------------
  134.     Add the hardwired escape sequences to the keyboard escape sequence    (UNIX)
  135.     tree.  This only needs to be here for people who don't have correct
  136.     termcap/info entries for these, which is almost everybody.  Since
  137.     these get added after the termcap/info versions of the same thing,
  138.     an escape sequence here that is the same as one there, or is a prefix
  139.     of one, or is a superset of one, will override the one from termcap.
  140.     So an incorrect termcap won't break things.  A correct termcap entry
  141.     that gets overwrote by an unfortunate coincidence will break things.
  142.     In order to reverse the priority and have termcap/info entries override
  143.     hardwired ones, define TERMCAP_WINS for os_unix.c in the
  144.     pico subdirectory.
  145.  
  146.    Args:  kbesc -- the trie used to store the escape sequences in
  147.  
  148.  Result: a fixed set of known escape sequences are added to the trie
  149.   ----------------------------------------------------------------------*/
  150. void
  151. setup_dflt_esc_seq(kbesc)
  152.     KBESC_T     **kbesc;
  153. {
  154.     /*
  155.      * this is sort of a hack [no kidding], but it allows us to use
  156.      * the function keys on pc's running telnet
  157.      *
  158.      * UW-NDC/UCS vt10[01] application mode.
  159.      */
  160.     kpinsert(kbesc, "\033OP", PF1);
  161.     kpinsert(kbesc, "\033OQ", PF2);
  162.     kpinsert(kbesc, "\033OR", PF3);
  163.     kpinsert(kbesc, "\033OS", PF4);
  164.     kpinsert(kbesc, "\033Op", PF5);
  165.     kpinsert(kbesc, "\033Oq", PF6);
  166.     kpinsert(kbesc, "\033Or", PF7);
  167.     kpinsert(kbesc, "\033Os", PF8);
  168.     kpinsert(kbesc, "\033Ot", PF9);
  169.     kpinsert(kbesc, "\033Ou", PF10);
  170.     kpinsert(kbesc, "\033Ov", PF11);
  171.     kpinsert(kbesc, "\033Ow", PF12);
  172.  
  173.     /*
  174.      * DEC vt100, ANSI and cursor key mode.
  175.      */
  176.     kpinsert(kbesc, "\033OA", KEY_UP);
  177.     kpinsert(kbesc, "\033OB", KEY_DOWN);
  178.     kpinsert(kbesc, "\033OC", KEY_RIGHT);
  179.     kpinsert(kbesc, "\033OD", KEY_LEFT);
  180.  
  181.     /*
  182.      * special keypad functions
  183.      */
  184.     kpinsert(kbesc, "\033[4J", KEY_PGUP);
  185.     kpinsert(kbesc, "\033[3J", KEY_PGDN);
  186.     kpinsert(kbesc, "\033[2J", KEY_HOME);
  187.     kpinsert(kbesc, "\033[N",  KEY_END);
  188.  
  189.     /*
  190.      * ANSI mode.
  191.      */
  192.     kpinsert(kbesc, "\033[=a", PF1);
  193.     kpinsert(kbesc, "\033[=b", PF2);
  194.     kpinsert(kbesc, "\033[=c", PF3);
  195.     kpinsert(kbesc, "\033[=d", PF4);
  196.     kpinsert(kbesc, "\033[=e", PF5);
  197.     kpinsert(kbesc, "\033[=f", PF6);
  198.     kpinsert(kbesc, "\033[=g", PF7);
  199.     kpinsert(kbesc, "\033[=h", PF8);
  200.     kpinsert(kbesc, "\033[=i", PF9);
  201.     kpinsert(kbesc, "\033[=j", PF10);
  202.     kpinsert(kbesc, "\033[=k", PF11);
  203.     kpinsert(kbesc, "\033[=l", PF12);
  204.  
  205.     /*
  206.      * DEC vt100, ANSI and cursor key mode reset
  207.      */
  208.     kpinsert(kbesc, "\033[A", KEY_UP);
  209.     kpinsert(kbesc, "\033[B", KEY_DOWN);
  210.     kpinsert(kbesc, "\033[C", KEY_RIGHT);
  211.     kpinsert(kbesc, "\033[D", KEY_LEFT);
  212.  
  213.     /*
  214.      * DEC vt52 mode.
  215.      */
  216.     kpinsert(kbesc, "\033A", KEY_UP);
  217.     kpinsert(kbesc, "\033B", KEY_DOWN);
  218.     kpinsert(kbesc, "\033C", KEY_RIGHT);
  219.     kpinsert(kbesc, "\033D", KEY_LEFT);
  220.  
  221.     /*
  222.      * DEC vt52 application keys, and some Zenith 19.
  223.      */
  224.     kpinsert(kbesc, "\033?r", KEY_DOWN);
  225.     kpinsert(kbesc, "\033?t", KEY_LEFT);
  226.     kpinsert(kbesc, "\033?v", KEY_RIGHT);
  227.     kpinsert(kbesc, "\033?x", KEY_UP);
  228.  
  229.     /*
  230.      * Sun Console sequences.
  231.      */
  232.     kpinsert(kbesc, "\033[1",   KEY_SWALLOW_Z);
  233.     kpinsert(kbesc, "\033[215", KEY_SWAL_UP);
  234.     kpinsert(kbesc, "\033[217", KEY_SWAL_LEFT);
  235.     kpinsert(kbesc, "\033[219", KEY_SWAL_RIGHT);
  236.     kpinsert(kbesc, "\033[221", KEY_SWAL_DOWN);
  237.  
  238.     /*
  239.      * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
  240.      */
  241.     kpinsert(kbesc, "\033_", KEY_KERMIT);
  242.  
  243.     /*
  244.      * Fake a control character.
  245.      */
  246.     kpinsert(kbesc, "\033\033", KEY_DOUBLE_ESC);
  247. }
  248.  
  249.  
  250.  
  251. /*----------------------------------------------------------------------
  252.    Set or clear the specified tty mode
  253.  
  254.    Args: ps --  struct pine
  255.      mode -- mode bits to modify
  256.      clear -- whether or not to clear or set
  257.  
  258.  Result: tty driver mode change. 
  259.   ----------------------------------------------------------------------*/
  260. void
  261. tty_chmod(ps, mode, func)
  262.     struct pine *ps;
  263.     int         mode;
  264.     int         func;
  265. {
  266.     char    *tty_name;
  267.     int         new_mode;
  268.     struct stat  sbuf;
  269.     static int   saved_mode = -1;
  270.  
  271.     /* if no problem figuring out tty's name & mode? */
  272.     if((((tty_name = (char *) ttyname(STDIN_FD)) != NULL
  273.      && fstat(STDIN_FD, &sbuf) == 0)
  274.     || ((tty_name = (char *) ttyname(STDOUT_FD)) != NULL
  275.         && fstat(STDOUT_FD, &sbuf) == 0))
  276.        && !(func == TMD_RESET && saved_mode < 0)){
  277.     new_mode = (func == TMD_RESET)
  278.              ? saved_mode
  279.              : (func == TMD_CLEAR)
  280.             ? (sbuf.st_mode & ~mode)
  281.             : (sbuf.st_mode | mode);
  282.     /* assign tty new mode */
  283.     if(chmod(tty_name, new_mode) == 0){
  284.         if(func == TMD_RESET)        /* forget we knew */
  285.           saved_mode = -1;
  286.         else if(saved_mode < 0)
  287.           saved_mode = sbuf.st_mode;    /* remember original */
  288.     }
  289.     }
  290. }
  291.  
  292.  
  293.  
  294. /*----------------------------------------------------------------------
  295.        End use of the tty, put it back into it's normal mode     (UNIX)
  296.  
  297.    Args: ps --  struct pine
  298.  
  299.  Result: tty driver mode change. 
  300.   ----------------------------------------------------------------------*/
  301. void
  302. end_tty_driver(ps)
  303.      struct pine *ps;
  304. {
  305.     ps = ps; /* get rid of unused parameter warning */
  306.  
  307. #ifdef    MOUSE
  308.     end_mouse();
  309. #endif    /* MOUSE */
  310.     fflush(stdout);
  311.     dprint(2, (debugfile, "about to end_tty_driver\n"));
  312.  
  313.     tty_chmod(ps, 0, TMD_RESET);
  314.     Raw(0);
  315. }
  316.  
  317.  
  318.  
  319. /*----------------------------------------------------------------------
  320.     Actually set up the tty driver                             (UNIX)
  321.  
  322.    Args: state -- which state to put it in. 1 means go into raw, 0 out of
  323.  
  324.   Result: returns 0 if successful and -1 if not.
  325.   ----*/
  326.  
  327. Raw(state)
  328. int state;
  329. {
  330.     /** state is either ON or OFF, as indicated by call **/
  331.     /* Check return code only on first call. If it fails we're done for and
  332.        if it goes OK the other will probably go OK too. */
  333.  
  334.     if (state == 0 && _inraw) {
  335.         /*----- restore state to original -----*/
  336. #ifdef    HAVE_TERMIOS
  337.     if (tcsetattr (STDIN_FD, TCSADRAIN, &_original_tty) < 0)
  338.         return -1;
  339. #else    /* HAVE_TERMIOS */
  340. #ifdef    HAVE_TERMIO
  341.         if(ioctl(STDIN_FD, TCSETAW, &_original_tty) < 0)
  342.           return(-1);
  343. #else
  344.     if(ioctl(STDIN_FD, TIOCSETP, &_original_tty) < 0)
  345.           return(-1);
  346.     (void) ioctl(STDIN_FD, TIOCSLTC, &_original_ltchars);
  347.     (void) ioctl(STDIN_FD, TIOCSETC, &_original_tchars);
  348.         (void) ioctl(STDIN_FD, TIOCLSET, &_original_lmode);
  349. #endif    /* HAVE_TERMIO */
  350. #endif    /* HAVE_TERMIOS */
  351.         _inraw = 0;
  352.     } else if (state == 1 && ! _inraw) {
  353.         /*----- Go into raw mode (cbreak actually) ----*/
  354.  
  355. #ifdef    HAVE_TERMIOS
  356.     if (tcgetattr (STDIN_FD, &_original_tty) < 0)
  357.         return -1;
  358.     tcgetattr (STDIN_FD, &_raw_tty);
  359.     _raw_tty.c_lflag &= ~(ICANON | ECHO | IEXTEN); /* noecho raw mode    */
  360.  
  361.      _raw_tty.c_lflag &= ~ISIG;        /* disable signals           */
  362.      _raw_tty.c_iflag &= ~ICRNL;        /* turn off CR->NL on input  */
  363.      _raw_tty.c_oflag &= ~ONLCR;        /* turn off NL->CR on output */
  364.  
  365.     /* Only go into 8 bit mode if we are doing something other
  366.      * than plain ASCII. This will save the folks that have
  367.      * their parity on their serial lines wrong thr trouble of
  368.      * getting it right
  369.      */
  370.         if(ps_global->VAR_CHAR_SET && ps_global->VAR_CHAR_SET[0] &&
  371.        strucmp(ps_global->VAR_CHAR_SET, "us-ascii"))
  372.       _raw_tty.c_iflag &= ~ISTRIP;        /* turn off hi bit stripping */
  373.  
  374.     _raw_tty.c_cc[VMIN]  = '\01';        /* min # of chars to queue  */
  375.     _raw_tty.c_cc[VTIME] = '\0';        /* min time to wait for input*/
  376.     _raw_tty.c_cc[VINTR] = ctrl('C');    /* make it our special char */
  377.     _raw_tty.c_cc[VQUIT] = 0;
  378.     _raw_tty.c_cc[VSUSP] = 0;
  379.     ps_global->low_speed = cfgetospeed(&_raw_tty) < B4800;
  380.     tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
  381. #else
  382. #ifdef    HAVE_TERMIO
  383.         if(ioctl(STDIN_FD, TCGETA, &_original_tty) < 0)
  384.           return(-1);
  385.     (void) ioctl(STDIN_FD, TCGETA, &_raw_tty);    /** again! **/
  386.  
  387.     _raw_tty.c_lflag &= ~(ICANON | ECHO);    /* noecho raw mode  */
  388.  
  389.      _raw_tty.c_lflag &= ~ISIG;        /* disable signals */
  390.  
  391.      _raw_tty.c_iflag &= ~ICRNL;        /* turn off CR->NL on input  */
  392.      _raw_tty.c_oflag &= ~ONLCR;        /* turn off NL->CR on output */
  393.     _raw_tty.c_cc[VMIN]  = 1;        /* min # of chars to queue   */
  394.     _raw_tty.c_cc[VTIME] = 0;        /* min time to wait for input*/
  395.     _raw_tty.c_cc[VINTR] = ctrl('C');    /* make it our special char */
  396.     _raw_tty.c_cc[VQUIT] = 0;
  397.         ps_global->low_speed = (_raw_tty.c_cflag&CBAUD) < (unsigned int)B4800;
  398.     (void) ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  399.  
  400. #else    /* HAVE_TERMIO */
  401.         if(ioctl(STDIN_FD, TIOCGETP, &_original_tty) < 0)
  402.           return(-1);
  403.     (void) ioctl(STDIN_FD, TIOCGETP, &_raw_tty);   
  404.         (void) ioctl(STDIN_FD, TIOCGETC, &_original_tchars);
  405.     (void) ioctl(STDIN_FD, TIOCGETC, &_raw_tchars);
  406.     (void) ioctl(STDIN_FD, TIOCGLTC, &_original_ltchars);
  407.     (void) ioctl(STDIN_FD, TIOCGLTC, &_raw_ltchars);
  408.         (void) ioctl(STDIN_FD, TIOCLGET, &_original_lmode);
  409.         (void) ioctl(STDIN_FD, TIOCLGET, &_raw_lmode);
  410.  
  411.     _raw_tty.sg_flags &= ~(ECHO);    /* echo off */
  412.     _raw_tty.sg_flags |= CBREAK;    /* raw on    */
  413.         _raw_tty.sg_flags &= ~CRMOD;    /* Turn off CR -> LF mapping */
  414.  
  415.     _raw_tchars.t_intrc = -1;    /* Turn off ^C and ^D */
  416.     _raw_tchars.t_eofc  = -1;
  417.  
  418. #ifdef    DEBUG
  419.     if(debug < 9)            /* only on if full debugging set */
  420. #endif
  421.     _raw_tchars.t_quitc = -1;    /* Turn off ^\ */
  422.  
  423.     _raw_ltchars.t_lnextc = -1;    /* Turn off ^V so we can use it */
  424.     _raw_ltchars.t_dsuspc = -1;    /* Turn off ^Y so we can use it */
  425.     _raw_ltchars.t_suspc  = -1;    /* Turn off ^Z; we just read 'em */
  426.     _raw_ltchars.t_werasc = -1;    /* Turn off ^w word erase */
  427.     _raw_ltchars.t_rprntc = -1;    /* Turn off ^R reprint line */
  428.         _raw_ltchars.t_flushc = -1;    /* Turn off ^O output flush */
  429.  
  430.     /* Only go into 8 bit mode if we are doing something other
  431.      * than plain ASCII. This will save the folks that have
  432.      * their parity on their serial lines wrong thr trouble of
  433.      * getting it right
  434.      */
  435.         if(ps_global->VAR_CHAR_SET && ps_global->VAR_CHAR_SET[0] &&
  436.        strucmp(ps_global->VAR_CHAR_SET, "us-ascii")) {
  437.         _raw_lmode |= LPASS8;
  438. #ifdef    NXT                /* Hope there aren't many like this! */
  439.             _raw_lmode |= LPASS8OUT;
  440. #endif
  441.     }
  442.             
  443.     (void) ioctl(STDIN_FD, TIOCSETP, &_raw_tty);
  444.     (void) ioctl(STDIN_FD, TIOCSLTC, &_raw_ltchars);
  445.         (void) ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
  446.         (void) ioctl(STDIN_FD, TIOCLSET, &_raw_lmode);
  447.         ps_global->low_speed =  (int)_raw_tty.sg_ispeed < B4800;
  448.  
  449. #endif
  450. #endif
  451.     _inraw = 1;
  452.     crlf_proc(0);
  453.     xonxoff_proc(F_ON(F_PRESERVE_START_STOP, ps_global));
  454.     }
  455.     return(0);
  456. }
  457.  
  458.  
  459.  
  460. /*----------------------------------------------------------------------
  461.     Set up the tty driver to use XON/XOFF flow control         (UNIX)
  462.  
  463.    Args: state -- True to make sure XON/XOFF turned on, FALSE off.
  464.  
  465.   Result: none.
  466.  
  467.   ----*/
  468. void
  469. xonxoff_proc(state)
  470.     int state;
  471. {
  472.     if(_inraw){
  473.     if(state){
  474. #ifdef    HAVE_TERMIOS
  475.         if(!(_raw_tty.c_iflag & IXON)){
  476.         _raw_tty.c_iflag |= IXON;
  477.         tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
  478.         }
  479. #else
  480. #ifdef    HAVE_TERMIO
  481.         if(!(_raw_tty.c_iflag & IXON)){
  482.         _raw_tty.c_iflag |= IXON;    /* turn ON ^S/^Q on input   */
  483.         (void) ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  484.         }
  485. #else    /* HAVE_TERMIO */
  486.         if(_raw_tchars.t_startc == -1 || _raw_tchars.t_stopc == -1){
  487.         _raw_tchars.t_startc = 'Q' - '@'; /* Turn ON ^S/^Q */
  488.         _raw_tchars.t_stopc  = 'S' - '@';
  489.         (void) ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
  490.         }
  491. #endif
  492. #endif
  493.     }
  494.     else if(F_OFF(F_PRESERVE_START_STOP, ps_global)){
  495. #ifdef    HAVE_TERMIOS
  496.         if(_raw_tty.c_iflag & IXON){
  497.         _raw_tty.c_iflag &= ~IXON;    /* turn off ^S/^Q on input   */
  498.         tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
  499.         }
  500. #else
  501. #ifdef    HAVE_TERMIO
  502.         if(_raw_tty.c_iflag & IXON){
  503.         _raw_tty.c_iflag &= ~IXON;    /* turn off ^S/^Q on input   */
  504.         (void) ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  505.         }
  506. #else    /* HAVE_TERMIO */
  507.         if(!(_raw_tchars.t_startc == -1 && _raw_tchars.t_stopc == -1)){
  508.         _raw_tchars.t_startc = -1;    /* Turn off ^S/^Q */
  509.         _raw_tchars.t_stopc  = -1;
  510.         (void) ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
  511.         }
  512. #endif
  513. #endif
  514.     }
  515.     }
  516. }
  517.  
  518.  
  519.  
  520. /*----------------------------------------------------------------------
  521.     Set up the tty driver to do LF->CR translation        (UNIX)
  522.  
  523.    Args: state -- True to turn on translation, false to write raw LF's
  524.  
  525.   Result: none.
  526.  
  527.   ----*/
  528. void
  529. crlf_proc(state)
  530.     int state;
  531. {
  532.     if(_inraw){
  533.     if(state){                /* turn ON NL->CR on output */
  534. #ifdef    HAVE_TERMIOS
  535.         if(!(_raw_tty.c_oflag & ONLCR)){
  536.         _raw_tty.c_oflag |= ONLCR;
  537.         tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
  538.         }
  539. #else
  540. #ifdef    HAVE_TERMIO
  541.         if(!(_raw_tty.c_oflag & ONLCR)){
  542.         _raw_tty.c_oflag |= ONLCR;
  543.         (void) ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  544.         }
  545. #else    /* HAVE_TERMIO */
  546.         if(!(_raw_tty.sg_flags & CRMOD)){
  547.         _raw_tty.sg_flags |= CRMOD;
  548.         (void) ioctl(STDIN_FD, TIOCSETP, &_raw_tty);
  549.         }
  550. #endif
  551. #endif
  552.     }
  553.     else{                    /* turn OFF NL-CR on output */
  554. #ifdef    HAVE_TERMIOS
  555.         if(_raw_tty.c_oflag & ONLCR){
  556.         _raw_tty.c_oflag &= ~ONLCR;
  557.         tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
  558.         }
  559. #else
  560. #ifdef    HAVE_TERMIO
  561.         if(_raw_tty.c_oflag & ONLCR){
  562.         _raw_tty.c_oflag &= ~ONLCR;
  563.         (void) ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  564.         }
  565. #else    /* HAVE_TERMIO */
  566.         if(_raw_tty.sg_flags & CRMOD){
  567.         _raw_tty.sg_flags &= ~CRMOD;
  568.         (void) ioctl(STDIN_FD, TIOCSETP, &_raw_tty);
  569.         }
  570. #endif
  571. #endif
  572.     }
  573.     }
  574. }
  575.  
  576.  
  577. /*----------------------------------------------------------------------
  578.     Set up the tty driver to hanle interrupt char        (UNIX)
  579.  
  580.    Args: state -- True to turn on interrupt char, false to not
  581.  
  582.   Result: tty driver that'll send us SIGINT or not
  583.  
  584.   ----*/
  585. void
  586. intr_proc(state)
  587.     int state;
  588. {
  589.     if(_inraw){
  590.     if(state){
  591. #ifdef HAVE_TERMIOS
  592.         _raw_tty.c_lflag |= ISIG;        /* enable signals */
  593.         tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
  594. #else
  595. #ifdef HAVE_TERMIO
  596.         _raw_tty.c_lflag |= ISIG;        /* enable signals */
  597.         (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  598. #else
  599.         _raw_tchars.t_intrc = ctrl('C');
  600.         (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
  601. #endif /* HAVE_TERMIO */
  602. #endif /* HAVE_TERMIOS */
  603.     }
  604.     else{
  605. #ifdef    HAVE_TERMIOS
  606.         _raw_tty.c_lflag &= ~ISIG;        /* disable signals */
  607.         tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
  608. #else
  609. #ifdef    HAVE_TERMIO
  610.         _raw_tty.c_lflag &= ~ISIG;        /* disable signals */
  611.         (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
  612. #else    /* HAVE_TERMIO */
  613.         _raw_tchars.t_intrc = -1;
  614.         (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
  615. #endif /* HAVE_TERMIO */
  616. #endif /* HAVE_TERMIOS */
  617.     }
  618.     }
  619. }
  620.  
  621.  
  622. #ifdef RESIZING
  623. jmp_buf winch_state;
  624. int     winch_occured = 0;
  625. int     ready_for_winch = 0;
  626. #endif
  627.  
  628. /*----------------------------------------------------------------------
  629.      This checks whether or not a character            (UNIX)
  630.      is ready to be read, or it times out.
  631.  
  632.     Args:  time_out --  number of seconds before it will timeout
  633.  
  634.   Result: Returns a NO_OP_IDLE or a NO_OP_COMMAND if the timeout expires
  635.       before input is available, or a KEY_RESIZE if a resize event
  636.       occurs, or READY_TO_READ if input is available before the timeout.
  637.   ----*/
  638. int
  639. check_for_timeout(time_out)
  640.      int time_out;
  641. {
  642. #ifdef USE_POLL
  643.      struct pollfd pollfd;
  644. #else
  645.      struct timeval tmo;
  646.      fd_set         readfds, errfds;
  647. #endif
  648.      int        res;
  649.      unsigned char  c;
  650.  
  651.      fflush(stdout);
  652.  
  653. #ifdef RESIZING
  654.      if(winch_occured || setjmp(winch_state) != 0) {
  655.          ready_for_winch = 0;
  656.      fix_windsize(ps_global);
  657.  
  658.      /*
  659.       * May need to unblock signal after longjmp from handler, because
  660.       * signal is normally unblocked upon routine exit from the handler.
  661.       */
  662.      if(!winch_occured)
  663.        pine_sigunblock(SIGWINCH);
  664.  
  665.          winch_occured   = 0;
  666.          return(KEY_RESIZE);
  667.      } else {
  668.          ready_for_winch = 1;
  669.      }
  670. #endif /* RESIZING */
  671.  
  672.      if(time_out > 0) {
  673.          /* Check to see if there's bytes to read with a timeout */
  674. #ifdef USE_POLL
  675.      pollfd.fd = STDIN_FD;
  676.      pollfd.events = POLLIN;
  677.      dprint(9,(debugfile,"poll event %d, timeout %d\n", pollfd.events,
  678.            time_out));
  679.      res = poll (&pollfd, 1, time_out * 1000);
  680.      dprint(9, (debugfile, "poll on tty returned %d, events %d\n",
  681.             res, pollfd.revents));
  682.      if((pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) && res >= 0){
  683.          if(pollfd.revents & POLLHUP)
  684.            read_bail();        /* non tragic */
  685.          else
  686.        res = -1;        /* exit below! */
  687.      }
  688. #else
  689.      FD_ZERO(&readfds);
  690.      FD_ZERO(&errfds);
  691.      FD_SET(STDIN_FD, &readfds);
  692.      FD_SET(STDIN_FD, &errfds);
  693.      tmo.tv_sec  = time_out;
  694.          tmo.tv_usec = 0; 
  695.  
  696.          dprint(9, (debugfile,"Select readfds:%d timeval:%d,%d\n", readfds,
  697.            tmo.tv_sec,tmo.tv_usec));
  698.  
  699.          res = select(STDIN_FD+1, &readfds, 0, &errfds, &tmo);
  700.  
  701.          dprint(9, (debugfile, "Select on tty returned %d\n", res));
  702. #endif
  703.  
  704.          if(res < 0) {
  705.              if(errno == EINTR || errno == EAGAIN) {
  706. #ifdef RESIZING
  707.                  ready_for_winch = 0;
  708. #endif
  709.                  return(NO_OP_COMMAND);
  710.              }
  711.              panic1("Select error: %s\n", error_description(errno));
  712.          }
  713.  
  714.          if(res == 0) { /* the select timed out */
  715.          if(getppid() == 1){
  716.          dprint(1, (debugfile,
  717.                 "\n\n** Parent found to be init!?!\n\n"));
  718.          read_bail();
  719.          /* NO RETURN */
  720.          }
  721.            
  722. #ifdef RESIZING
  723.              ready_for_winch = 0;
  724. #endif
  725.              return(time_out > 25 ? NO_OP_IDLE: NO_OP_COMMAND);
  726.          }
  727.      }
  728.  
  729. #ifdef RESIZING
  730.      ready_for_winch = 0;
  731. #endif
  732.  
  733.      return(READY_TO_READ);
  734. }
  735.  
  736.  
  737. /*----------------------------------------------------------------------
  738.      Lowest level read command. This reads one character.    (UNIX)
  739.  
  740.   Result: Returns the single character read or a NO_OP_COMMAND if the
  741.           read was interrupted.
  742.   ----*/
  743. int
  744. read_a_char()
  745. {
  746.      int        res;
  747.      unsigned char  c;
  748.  
  749.      res = read(STDIN_FD, &c, 1);
  750.  
  751.      if(res <= 0) {
  752.      /*
  753.       * Error reading from terminal!
  754.       * The only acceptable failure is being interrupted.  If so,
  755.       * return a value indicating such...
  756.       */
  757.      if(res < 0 && errno == EINTR){
  758.          dprint(2, (debugfile, "read_a_char interrupted\n"));
  759.          RETURN_CH(NO_OP_COMMAND);
  760.      }
  761.  
  762.      /*
  763.       * Else we read EOF or otherwise encountered some catastrophic
  764.       * error.  Treat it like SIGHUP (i.e., clean up and exit).
  765.       */
  766.      dprint(1, (debugfile, "\n\n** Error reading from tty : %s\n\n",
  767.             (res == 0) ? "EOF" : error_description(errno)));
  768.  
  769.      read_bail();
  770.      /* NO RETURN */
  771.      }
  772.  
  773.      dprint(9, (debugfile, "read_a_char return '\\%03o'\n", (int)c));
  774.      RETURN_CH((int)c);
  775. }
  776.  
  777.  
  778. /*----------------------------------------------------------------------
  779.      Simple version of read_a_char with simple error handling
  780.  
  781.   Result: Returns read character or it never returns
  782.   ----*/
  783. int
  784. getchar_for_kbseq()
  785. {
  786.     int          res;
  787.     unsigned char c;
  788.  
  789.     while((res = read(STDIN_FD, &c, 1)) <= 0)
  790.       if(!(res < 0 && errno == EINTR))
  791.     read_bail();
  792.     /* NO RETURN */
  793.  
  794.     RETURN_CH((int) c);
  795. }
  796.  
  797.  
  798. /*----------------------------------------------------------------------
  799.   Read input characters with lots of processing for arrow keys and such  (UNIX)
  800.  
  801.  Args:  time_out -- The timeout to for the reads 
  802.  
  803.  Result: returns the character read. Possible special chars.
  804.  
  805.     This deals with function and arrow keys as well. 
  806.  
  807.   The idea is that this routine handles all escape codes so it done in
  808.   only one place. Especially so the back arrow key can work when entering
  809.   things on a line. Also so all function keys can be disabled and not
  810.   cause weird things to happen.
  811.   ---*/
  812. int
  813. read_char(time_out)
  814.     int time_out;
  815. {
  816.     int ch, status, cc;
  817.  
  818.     /* Get input from initial-keystrokes */
  819.     if(process_config_input(&ch))
  820.       return(ch);
  821.  
  822.     /*
  823.      * We only check for timeouts at the start of read_char, not in the
  824.      * middle of escape sequences.
  825.      */
  826.     ch = check_for_timeout(time_out);
  827.     if(ch == NO_OP_IDLE || ch == NO_OP_COMMAND || ch == KEY_RESIZE)
  828.       goto done;
  829.  
  830.     switch(status = kbseq(ps_global->kbesc, getchar_for_kbseq, &ch)){
  831.       case KEY_DOUBLE_ESC:
  832.     /*
  833.      * Special hack to get around comm devices eating control characters.
  834.      */
  835.     if(check_for_timeout(5) != READY_TO_READ){
  836.         ch = KEY_JUNK;        /* user typed ESC ESC, then stopped */
  837.         goto done;
  838.     }
  839.     else
  840.       ch = read_a_char();
  841.  
  842.     ch &= 0x7f;
  843.     if(isdigit((unsigned char)ch)){
  844.         int n = 0, i = ch - '0';
  845.  
  846.         if(i < 0 || i > 2){
  847.         ch = KEY_JUNK;
  848.         goto done;        /* bogus literal char value */
  849.         }
  850.  
  851.         while(n++ < 2){
  852.         if(check_for_timeout(5) != READY_TO_READ
  853.            || (!isdigit((unsigned char) (ch = read_a_char()))
  854.                || (n == 1 && i == 2 && ch > '5')
  855.                || (n == 2 && i == 25 && ch > '5'))){
  856.             ch = KEY_JUNK;    /* user typed ESC ESC #, stopped */
  857.             goto done;
  858.         }
  859.  
  860.         i = (i * 10) + (ch - '0');
  861.         }
  862.  
  863.         ch = i;
  864.     }
  865.     else{
  866.         if(islower((unsigned char)ch))    /* canonicalize if alpha */
  867.           ch = toupper((unsigned char)ch);
  868.  
  869.         ch = (isalpha((unsigned char)ch) || ch == '@'
  870.           || (ch >= '[' && ch <= '_'))
  871.            ? ctrl(ch) : ((ch == SPACE) ? ctrl('@'): ch);
  872.     }
  873.  
  874.     goto done;
  875.  
  876. #ifdef MOUSE
  877.       case KEY_XTERM_MOUSE:
  878.     if(mouseexist()){
  879.         /*
  880.          * special hack to get mouse events from an xterm.
  881.          * Get the details, then pass it past the keymenu event
  882.          * handler, and then to the installed handler if there
  883.          * is one...
  884.          */
  885.         static int down = 0;
  886.         int        button, x, y;
  887.         unsigned   cmd;
  888.  
  889.         clear_cursor_pos();
  890.         ch = read_a_char();
  891.         button = ch & 0x03;
  892.  
  893.         ch = read_a_char();
  894.         x = ch - '!';
  895.  
  896.         ch = read_a_char();
  897.  
  898.         y = ch - '!';
  899.  
  900.         ch = NO_OP_COMMAND;
  901.         if(button == 0){        /* xterm button 1 down */
  902.         down = 1;
  903.         if(checkmouse(&cmd, 1, x, y))
  904.           ch = (int)cmd;
  905.         }
  906.         else if (down && button == 3){
  907.         down = 0;
  908.         if(checkmouse(&cmd, 0, x, y))
  909.           ch = (int)cmd;
  910.         }
  911.  
  912.         goto done;
  913.     }
  914.  
  915.     break;
  916. #endif /* MOUSE */
  917.  
  918.       case  KEY_UP    :
  919.       case  KEY_DOWN    :
  920.       case  KEY_RIGHT    :
  921.       case  KEY_LEFT    :
  922.       case  KEY_PGUP    :
  923.       case  KEY_PGDN    :
  924.       case  KEY_HOME    :
  925.       case  KEY_END    :
  926.       case  KEY_DEL    :
  927.       case  PF1        :
  928.       case  PF2        :
  929.       case  PF3        :
  930.       case  PF4        :
  931.       case  PF5        :
  932.       case  PF6        :
  933.       case  PF7        :
  934.       case  PF8        :
  935.       case  PF9        :
  936.       case  PF10    :
  937.       case  PF11    :
  938.       case  PF12    :
  939.         dprint(9, (debugfile, "Read char returning: %d %s\n",
  940.                    status, pretty_command(status)));
  941.     return(status);
  942.  
  943.       case KEY_SWALLOW_Z:
  944.     status = KEY_JUNK;
  945.       case KEY_SWAL_UP:
  946.       case KEY_SWAL_DOWN:
  947.       case KEY_SWAL_LEFT:
  948.       case KEY_SWAL_RIGHT:
  949.     do
  950.       if(check_for_timeout(2) != READY_TO_READ){
  951.           status = KEY_JUNK;
  952.           break;
  953.       }
  954.     while(!strchr("~qz", read_a_char()));
  955.     ch = (status == KEY_JUNK) ? status : status - (KEY_SWAL_UP - KEY_UP);
  956.     goto done;
  957.  
  958.       case KEY_KERMIT:
  959.     do{
  960.         cc = ch;
  961.         if(check_for_timeout(2) != READY_TO_READ){
  962.         status = KEY_JUNK;
  963.         break;
  964.         }
  965.         else
  966.           ch = read_a_char();
  967.     }
  968.     while(cc != '\033' && ch != '\\');
  969.  
  970.     ch = KEY_JUNK;
  971.     goto done;
  972.  
  973.       case BADESC:
  974.     ch = KEY_JUNK;
  975.     goto done;
  976.  
  977.       case 0:     /* regular character */
  978.       default:
  979.     /*
  980.      * we used to strip (ch &= 0x7f;), but this seems much cleaner
  981.      * in the face of line noise and has the benefit of making it
  982.      * tougher to emit mistakenly labeled MIME...
  983.      */
  984.     if((ch & 0x80) && (!ps_global->VAR_CHAR_SET
  985.                || !strucmp(ps_global->VAR_CHAR_SET, "US-ASCII"))){
  986.         dprint(9, (debugfile, "Read char returning: %d %s\n",
  987.                status, pretty_command(status)));
  988.         return(KEY_JUNK);
  989.     }
  990.     else if(ch == ctrl('Z')){
  991.         dprint(9, (debugfile, "Read char calling do_suspend\n"));
  992.         return(do_suspend(ps_global));
  993.     }
  994.  
  995.  
  996.       done:
  997.         dprint(9, (debugfile, "Read char returning: %d %s\n",
  998.                    ch, pretty_command(ch)));
  999.         return(ch);
  1000.     }
  1001. }
  1002.  
  1003.  
  1004. /*----------------------------------------------------------------------
  1005.   Reading input somehow failed and we need to shutdown now
  1006.  
  1007.  Args:  none
  1008.  
  1009.  Result: pine exits
  1010.  
  1011.   ---*/
  1012. void
  1013. read_bail()
  1014. {
  1015.     end_signals(1);
  1016.     if(ps_global->inbox_stream){
  1017.     if(ps_global->inbox_stream == ps_global->mail_stream)
  1018.       ps_global->mail_stream = NULL;
  1019.  
  1020.     if(!ps_global->inbox_stream->lock)        /* shouldn't be... */
  1021.       mail_close(ps_global->inbox_stream);
  1022.     }
  1023.  
  1024.     if(ps_global->mail_stream && !ps_global->mail_stream->lock)
  1025.       mail_close(ps_global->mail_stream);
  1026.  
  1027.     end_keyboard(F_ON(F_USE_FK,ps_global));
  1028.     end_tty_driver(ps_global);
  1029.     if(filter_data_file(0))
  1030.       unlink(filter_data_file(0));
  1031.  
  1032.     exit(0);
  1033. }
  1034.  
  1035.  
  1036. extern char term_name[]; /* term_name from ttyout.c-- affect keyboard*/
  1037. /* -------------------------------------------------------------------
  1038.      Set up the keyboard -- usually enable some function keys  (UNIX)
  1039.  
  1040.     Args: struct pine 
  1041.  
  1042. So far all we do here is turn on keypad mode for certain terminals
  1043.  
  1044. Hack for NCSA telnet on an IBM PC to put the keypad in the right mode.
  1045. This is the same for a vtXXX terminal or [zh][12]9's which we have 
  1046. a lot of at UW
  1047.   ----*/
  1048. void
  1049. init_keyboard(use_fkeys)
  1050.      int use_fkeys;
  1051. {
  1052.     if(use_fkeys && (!strucmp(term_name,"vt102")
  1053.              || !strucmp(term_name,"vt100")))
  1054.       printf("\033\133\071\071\150");
  1055. }
  1056.  
  1057.  
  1058.  
  1059. /*----------------------------------------------------------------------
  1060.      Clear keyboard, usually disable some function keys           (UNIX)
  1061.  
  1062.    Args:  pine state (terminal type)
  1063.  
  1064.  Result: keyboard state reset
  1065.   ----*/
  1066. void
  1067. end_keyboard(use_fkeys)
  1068.      int use_fkeys;
  1069. {
  1070.     if(use_fkeys && (!strcmp(term_name, "vt102")
  1071.              || !strcmp(term_name, "vt100"))){
  1072.     printf("\033\133\071\071\154");
  1073.     fflush(stdout);
  1074.     }
  1075. }
  1076.  
  1077.     
  1078. /*----------------------------------------------------------------------
  1079.    Discard any pending input characters                (UNIX)
  1080.  
  1081.    Args:  none
  1082.  
  1083.  Result: pending input buffer flushed
  1084.   ----*/
  1085. void
  1086. flush_input()
  1087. {
  1088. #ifdef    HAVE_TERMIOS
  1089.     tcflush(STDIN_FD, TCIFLUSH);
  1090. #else
  1091. #ifdef    HAVE_TERMIO
  1092.     ioctl(STDIN_FD, TCFLSH, 0);
  1093. #else
  1094. #ifdef    TIOCFLUSH
  1095. #ifdef    FREAD
  1096.     int i = FREAD;
  1097. #else
  1098.     int i = 1;
  1099. #endif
  1100.  
  1101.     ioctl(STDIN_FD, TIOCFLUSH, &i);
  1102. #else
  1103. #endif    /* TIOCFLUSH */
  1104. #endif    /* HAVE_TERMIO */
  1105. #endif    /* HAVE_TERMIOS */
  1106. }
  1107.  
  1108.     
  1109. #else
  1110. /*
  1111.  * DOS && OS/2 specific code.
  1112.  * Middle of giant switch between UNIX and DOS/OS2 input drivers
  1113.  */
  1114.  
  1115.  
  1116. #ifdef OS2
  1117. #define INCL_BASE
  1118. #define INCL_DOS
  1119. #define INCL_VIO
  1120. #define INCL_KBD
  1121. #define INCL_NOPM
  1122. #include <os2.h>
  1123. #undef ADDRESS
  1124. #endif
  1125.  
  1126. #include "headers.h"
  1127.  
  1128.  
  1129. /*
  1130.  * Internal prototypes
  1131.  */
  1132. void line_paint PROTO((int, int *));
  1133. int  process_config_input PROTO((int *));
  1134.  
  1135.  
  1136.  
  1137. #if    !(defined(WIN32) || defined(OS2))
  1138. #include <dos.h>
  1139. #include <bios.h>
  1140. #endif
  1141.  
  1142. /* global to tell us if we have an enhanced keyboard! */
  1143. static int enhanced = 0;
  1144. /* global function to execute while waiting for character input */
  1145. void   (*while_waiting)() = NULL;
  1146.  
  1147. #ifdef _WINDOWS
  1148. /* global to tell us if the window was resized. */
  1149. static int DidResize = FALSE;
  1150.  
  1151.  
  1152. /*----------------------------------------------------------------------
  1153.     Flag the fact the window has resized.
  1154. */
  1155. int
  1156. pine_window_resize_callback ()
  1157. {
  1158.     DidResize = TRUE;
  1159. }
  1160. #endif
  1161.  
  1162.  
  1163.  
  1164. /*----------------------------------------------------------------------
  1165.     Initialize the tty driver to do single char I/O and whatever else  (DOS)
  1166.  
  1167.  Input:  struct pine
  1168.  
  1169.  Result: tty driver is put in raw mode
  1170.   ----------------------------------------------------------------------*/
  1171. init_tty_driver(pine)
  1172.      struct pine *pine;
  1173. {
  1174. #ifdef _WINDOWS
  1175.     mswin_setresizecallback (pine_window_resize_callback);
  1176.     init_mouse ();            /* always a mouse under windows? */
  1177. #else
  1178. #ifdef OS2
  1179.     enhanced = 1;
  1180. #else
  1181.     /* detect enhanced keyboard */
  1182.     enhanced = enhanced_keybrd();    /* are there extra keys? */
  1183. #endif
  1184. #endif
  1185.     pine = pine;            /* Get rid of unused parm warning */
  1186.     return(Raw(1));
  1187. }
  1188.  
  1189.  
  1190.  
  1191. /*----------------------------------------------------------------------
  1192.        End use of the tty, put it back into it's normal mode          (DOS)
  1193.  
  1194.  Input:  struct pine
  1195.  
  1196.  Result: tty driver mode change
  1197.   ----------------------------------------------------------------------*/
  1198. void
  1199. end_tty_driver(pine)
  1200.      struct pine *pine;
  1201. {
  1202.     dprint(2, (debugfile, "about to end_tty_driver\n"));
  1203. #ifdef _WINDOWS
  1204.     mswin_clearresizecallback (pine_window_resize_callback);
  1205. #endif
  1206. }
  1207.  
  1208. /*----------------------------------------------------------------------
  1209.    translate IBM Keyboard Extended Functions to things pine understands.
  1210.    More work can be done to make things like Home, PageUp and PageDown work. 
  1211.  
  1212. /*
  1213.  * extended_code - return special key definition
  1214.  */
  1215. extended_code(kc)
  1216. unsigned  kc;
  1217. {
  1218.     switch(kc){
  1219. #ifdef    _WINDOWS
  1220.     case MSWIN_KEY_F1: return(PF1);
  1221.     case MSWIN_KEY_F2: return(PF2);
  1222.     case MSWIN_KEY_F3: return(PF3);
  1223.     case MSWIN_KEY_F4: return(PF4);
  1224.     case MSWIN_KEY_F5: return(PF5);
  1225.     case MSWIN_KEY_F6: return(PF6);
  1226.     case MSWIN_KEY_F7: return(PF7);
  1227.     case MSWIN_KEY_F8: return(PF8);
  1228.     case MSWIN_KEY_F9: return(PF9);
  1229.     case MSWIN_KEY_F10: return(PF10);
  1230.     case MSWIN_KEY_F11: return(PF11);
  1231.     case MSWIN_KEY_F12: return(PF12);
  1232.  
  1233.     case MSWIN_KEY_UP: return(KEY_UP);
  1234.     case MSWIN_KEY_DOWN: return(KEY_DOWN);
  1235.     case MSWIN_KEY_LEFT: return(KEY_LEFT);
  1236.     case MSWIN_KEY_RIGHT: return(KEY_RIGHT);
  1237.     case MSWIN_KEY_HOME: return(KEY_HOME);
  1238.     case MSWIN_KEY_END: return(KEY_END);
  1239.     case MSWIN_KEY_SCROLLUPPAGE:
  1240.     case MSWIN_KEY_PREVPAGE: return(KEY_PGUP);
  1241.     case MSWIN_KEY_SCROLLDOWNPAGE:
  1242.     case MSWIN_KEY_NEXTPAGE: return(KEY_PGDN);
  1243.     case MSWIN_KEY_DELETE: return(KEY_DEL);
  1244.     case MSWIN_KEY_SCROLLUPLINE: return (KEY_SCRLUPL);
  1245.     case MSWIN_KEY_SCROLLDOWNLINE: return (KEY_SCRLDNL);
  1246.     case MSWIN_KEY_SCROLLTO: return (KEY_SCRLTO);
  1247.  
  1248.     case MSWIN_KEY_NODATA:    return (NO_OP_COMMAND);
  1249. #else
  1250.     case 0x3b00 : return(PF1);
  1251.     case 0x3c00 : return(PF2);
  1252.     case 0x3d00 : return(PF3);
  1253.     case 0x3e00 : return(PF4);
  1254.     case 0x3f00 : return(PF5);
  1255.     case 0x4000 : return(PF6);
  1256.     case 0x4100 : return(PF7);
  1257.     case 0x4200 : return(PF8);
  1258.     case 0x4300 : return(PF9);
  1259.     case 0x4400 : return(PF10);
  1260.     case 0x8500 : return(PF11);
  1261.     case 0x8600 : return(PF12);
  1262.  
  1263.     case 0x4800 : return(KEY_UP);
  1264.     case 0x5000 : return(KEY_DOWN);
  1265.     case 0x4b00 : return(KEY_LEFT);
  1266.     case 0x4d00 : return(KEY_RIGHT);
  1267.     case 0x4700 : return(KEY_HOME);
  1268.     case 0x4f00 : return(KEY_END);
  1269.     case 0x4900 : return(KEY_PGUP);
  1270.     case 0x5100 : return(KEY_PGDN);
  1271.     case 0x5300 : return(KEY_DEL);
  1272.     case 0x48e0 : return(KEY_UP);            /* grey key version */
  1273.     case 0x50e0 : return(KEY_DOWN);            /* grey key version */
  1274.     case 0x4be0 : return(KEY_LEFT);            /* grey key version */
  1275.     case 0x4de0 : return(KEY_RIGHT);        /* grey key version */
  1276.     case 0x47e0 : return(KEY_HOME);            /* grey key version */
  1277.     case 0x4fe0 : return(KEY_END);            /* grey key version */
  1278.     case 0x49e0 : return(KEY_PGUP);            /* grey key version */
  1279.     case 0x51e0 : return(KEY_PGDN);            /* grey key version */
  1280.     case 0x53e0 : return(KEY_DEL);            /* grey key version */
  1281. #endif
  1282.     default   : return(NO_OP_COMMAND);
  1283.     }
  1284. }
  1285.  
  1286.  
  1287.  
  1288. /*----------------------------------------------------------------------
  1289.    Read input characters with lots of processing for arrow keys and such (DOS)
  1290.  
  1291.  Input:  none
  1292.  
  1293.  Result: returns the character read. Possible special chars defined h file
  1294.  
  1295.  
  1296.     This deals with function and arrow keys as well. 
  1297.   It returns ^T for up , ^U for down, ^V for forward and ^W for back.
  1298.   These are just sort of arbitrarily picked and might be changed.
  1299.   They are defined in defs.h. Didn't want to use 8 bit chars because
  1300.   the values are signed chars, though it ought to work with negative 
  1301.   values. 
  1302.  
  1303.   The idea is that this routine handles all escape codes so it done in
  1304.   only one place. Especially so the back arrow key can work when entering
  1305.   things on a line. Also so all function keys can be broken and not
  1306.   cause weird things to happen.
  1307. ----------------------------------------------------------------------*/
  1308.  
  1309. int
  1310. read_char(tm)
  1311. int tm;
  1312. {
  1313.     unsigned   ch = 0;
  1314.     long       timein;
  1315. #ifndef    _WINDOWS
  1316.     unsigned   intrupt = 0;
  1317.     extern int win_multiplex();
  1318. #endif
  1319.  
  1320.     if(process_config_input((int *) &ch))
  1321.       RETURN_CH(ch);
  1322.  
  1323. #ifdef _WINDOWS
  1324.     if (DidResize) {
  1325.      DidResize = FALSE;
  1326.      RETURN_CH (get_windsize (ps_global->ttyo));
  1327.     }
  1328. #endif
  1329.  
  1330. #ifdef OS2
  1331.     vidUpdate();
  1332. #endif
  1333. #ifdef MOUSE
  1334.     mouseon();
  1335. #endif
  1336.  
  1337.     if(tm){
  1338.     timein = time(0L);
  1339. #ifdef _WINDOWS
  1340.     /* mswin_charavail() Yeilds control to other window apps. */
  1341.     while (!mswin_charavail()) {
  1342. #else
  1343. #ifdef OS2
  1344.     while (!kbd_ready()) {
  1345. #else
  1346.     while(!_bios_keybrd(enhanced ? _NKEYBRD_READY : _KEYBRD_READY)){
  1347. #endif
  1348. #endif
  1349.         if(time(0L) >= timein+tm){
  1350.         ch = NO_OP_COMMAND;
  1351.         goto gotone;
  1352.         }
  1353. #ifdef _WINDOWS
  1354.         if (DidResize) {
  1355.         DidResize = FALSE;
  1356.         RETURN_CH( get_windsize (ps_global->ttyo));
  1357.         }
  1358. #endif
  1359. #ifdef    MOUSE
  1360.          if(checkmouse(&ch,0,0,0))
  1361.           goto gotone;
  1362. #endif
  1363.         if(while_waiting)
  1364.           (*while_waiting)();
  1365.  
  1366. #ifndef    _WINDOWS
  1367.         /*
  1368.          * the number "30" was not reached via experimentation
  1369.          * or scientific analysis of any kind.
  1370.          */
  1371.         if(((intrupt++) % 30) == 0)    /* surrender CPU to windows */
  1372.           win_multiplex();
  1373. #endif
  1374.     }
  1375.     }
  1376.  
  1377. #ifdef _WINDOWS
  1378.     ch = mswin_getc_fast();
  1379. #else
  1380. #ifdef OS2
  1381.     ch = kbd_getkey();
  1382. #else
  1383.     ch = _bios_keybrd(enhanced ? _NKEYBRD_READ : _KEYBRD_READ);
  1384. #endif
  1385. #endif
  1386.  
  1387. gotone:
  1388. #if defined(MOUSE)
  1389.     mouseoff();
  1390.  
  1391.     /* More obtuse key mapping.  If it is a mouse event, the return
  1392.      * may be KEY_MOUSE, which indicates to the upper layer that it
  1393.      * is a mouse event.  Return it here to avoid the code that
  1394.      * follows which would do a (ch & 0xff).
  1395.      */
  1396.     if (ch == KEY_MOUSE)
  1397.       RETURN_CH(ch);
  1398. #endif
  1399.  
  1400.     /*
  1401.      * WARNING: Hack notice.
  1402.      * the mouse interaction complicates this expression a bit as 
  1403.      * if function key mode is set, PFn values are setup for return
  1404.      * by the mouse event catcher.  For now, just special case them
  1405.      * since they don't conflict with any of the DOS special keys.
  1406.      */
  1407. #ifdef _WINDOWS
  1408.  
  1409.     if (ch >= MSWIN_RANGE_START && ch <= MSWIN_RANGE_END)
  1410.         RETURN_CH (extended_code (ch));
  1411.  
  1412.     RETURN_CH (ch & KEY_MASK);
  1413. #else /* DOS */
  1414.     if((ch & 0xff) == ctrl('Z'))
  1415.       RETURN_CH(do_suspend(ps_global));
  1416.  
  1417.     RETURN_CH((ch >= PF1 && ch <= PF12)
  1418.            ? ch
  1419.            : ((ch&0xff) && ((ch&0xff) != 0xe0))
  1420.           ? (ch&0xff)
  1421.           : extended_code(ch));
  1422. #endif
  1423. }
  1424.  
  1425. #ifdef OS2
  1426. static KBDINFO initialKbdInfo;
  1427. #endif
  1428.  
  1429. /* -------------------------------------------------------------------
  1430.      Set up the keyboard -- usually enable some function keys     (DOS)
  1431.  
  1432.   Input: struct pine (terminal type)
  1433.  
  1434.   Result: keyboard set up
  1435.  
  1436. -----------------------------------------------------------------------*/
  1437. void
  1438. init_keyboard(use_fkeys)
  1439.      int use_fkeys;
  1440. {
  1441. #ifdef OS2
  1442.   KBDINFO kbdInfo;
  1443.   KbdGetStatus(&initialKbdInfo, 0);
  1444.   kbdInfo = initialKbdInfo;
  1445.   kbdInfo.fsMask &= ~(0x0001|0x0008|0x0100); /* echo cooked off */
  1446.   kbdInfo.fsMask |= (0x002|0x004|0x0100); /* noecho,raw,shiftrpt on */
  1447.   KbdSetStatus(&kbdInfo, 0);
  1448. #endif
  1449. }
  1450.  
  1451.  
  1452.  
  1453. /*----------------------------------------------------------------------
  1454.      Clear keyboard, usually disable some function keys            (DOS)
  1455.  
  1456.  Input:  pine state (terminal type)
  1457.  
  1458.  Result: keyboard state reset
  1459.   ----------------------------------------------------------------------*/
  1460. /* BUG shouldn't have to check for pine != NULL */
  1461. void
  1462. end_keyboard(use_fkeys)
  1463.      int use_fkeys;
  1464. {
  1465. #ifdef OS2
  1466.   KbdSetStatus(&initialKbdInfo, 0);
  1467. #endif
  1468. }
  1469.  
  1470.  
  1471.  
  1472. /*----------------------------------------------------------------------
  1473.    Discard any pending input characters                (DOS)
  1474.  
  1475.    Args:  none
  1476.  
  1477.  Result: pending input buffer flushed
  1478.   ----*/
  1479. void
  1480. flush_input()
  1481. {
  1482. #ifdef _WINDOWS
  1483.     while (mswin_charavail ())
  1484.         (void) mswin_getc ();
  1485. #else
  1486. #ifdef OS2
  1487.     kbd_flush();
  1488. #else
  1489.     while(_bios_keybrd(enhanced ? _NKEYBRD_READY : _KEYBRD_READY))
  1490.       (void) _bios_keybrd(enhanced ? _NKEYBRD_READ : _KEYBRD_READ);
  1491. #endif
  1492. #endif
  1493. }
  1494.  
  1495.     
  1496. /*----------------------------------------------------------------------
  1497.     Actually set up the tty driver                             (DOS)
  1498.  
  1499.    Args: state -- which state to put it in. 1 means go into raw, 0 out of
  1500.  
  1501.   Result: returns 0 if successful and -1 if not.
  1502.   ----*/
  1503.  
  1504. Raw(state)
  1505. int state;
  1506. {
  1507. #ifdef OS2
  1508.     KBDINFO ki = initialKbdInfo;
  1509.     if (state)
  1510.     {
  1511.         ki.fsMask &= ~(0x0001|0x0008|0x0100); /* echo cooked off */
  1512.         ki.fsMask |= (0x002|0x004|0x0100); /* noecho,raw,shiftrpt on */
  1513.     }
  1514.     KbdSetStatus(&ki, 0);
  1515. #endif
  1516.  
  1517. /* of course, DOS never runs at low speed!!! */
  1518.     ps_global->low_speed = 0;
  1519.     return(0);
  1520. }
  1521.  
  1522.  
  1523. /*----------------------------------------------------------------------
  1524.     Set up the tty driver to use XON/XOFF flow control        (DOS)
  1525.  
  1526.    Args: state -- True to make sure XON/XOFF turned on, FALSE default state
  1527.  
  1528.   Result: none.
  1529.   ----*/
  1530. void
  1531. xonxoff_proc(state)
  1532.     int state;
  1533. {
  1534.     return;                    /* no op */
  1535. }
  1536.  
  1537.  
  1538. /*----------------------------------------------------------------------
  1539.     Set up the tty driver to do LF->CR translation        (DOS)
  1540.  
  1541.    Args: state -- True to turn on translation, false to write raw LF's
  1542.  
  1543.   Result: none.
  1544.  
  1545.   ----*/
  1546. void
  1547. crlf_proc(state)
  1548.     int state;
  1549. {
  1550.     return;                    /* no op */
  1551. }
  1552.  
  1553.  
  1554. /*----------------------------------------------------------------------
  1555.     Set up the tty driver to hanle interrupt char        (DOS)
  1556.  
  1557.    Args: state -- True to turn on interrupt char, false to not
  1558.  
  1559.   Result: tty driver that'll send us SIGINT or not
  1560.  
  1561.   ----*/
  1562. void
  1563. intr_proc(state)
  1564.     int state;
  1565. {
  1566.     return;                    /* no op */
  1567. }
  1568. #endif /* DOS End of giant switch between UNX and DOS input drivers */
  1569.  
  1570.  
  1571. /*----------------------------------------------------------------------
  1572.         Read a character from keyboard with timeout
  1573.  Input:  none
  1574.  
  1575.  Result: Returns command read via read_char
  1576.          Times out and returns a null command every so often
  1577.  
  1578.   Calculates the timeout for the read, and does a few other house keeping 
  1579. things.  The duration of the timeout is set in pine.c.
  1580.   ----------------------------------------------------------------------*/
  1581. int
  1582. read_command()
  1583. {
  1584.     int ch, tm = 0;
  1585.     long dtime; 
  1586.  
  1587.     cancel_busy_alarm(-1);
  1588.     tm = (messages_queued(&dtime) > 1) ? (int)dtime : timeout;
  1589.  
  1590.     ch = read_char(tm);
  1591.     dprint(9, (debugfile, "Read command returning: %d %s\n", ch,
  1592.               pretty_command(ch)));
  1593.     if(ch != NO_OP_COMMAND && ch != NO_OP_IDLE && ch != KEY_RESIZE)
  1594.       zero_new_mail_count();
  1595.  
  1596. #ifdef    BACKGROUND_POST
  1597.     /*
  1598.      * Any expired children to report on?
  1599.      */
  1600.     if(ps_global->post && ps_global->post->pid == 0){
  1601.     int   winner = 0;
  1602.  
  1603.     if(ps_global->post->status < 0){
  1604.         q_status_message(SM_ORDER | SM_DING, 3, 3, "Abysmal failure!");
  1605.     }
  1606.     else{
  1607.         (void) pine_send_status(ps_global->post->status,
  1608.                     ps_global->post->fcc, tmp_20k_buf,
  1609.                     &winner);
  1610.         q_status_message(SM_ORDER | (winner ? 0 : SM_DING), 3, 3,
  1611.                  tmp_20k_buf);
  1612.  
  1613.     }
  1614.  
  1615.     if(!winner)
  1616.       q_status_message(SM_ORDER, 0, 3,
  1617.       "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");
  1618.  
  1619.     if(ps_global->post->fcc)
  1620.       fs_give((void **) &ps_global->post->fcc);
  1621.  
  1622.     fs_give((void **) &ps_global->post);
  1623.     }
  1624. #endif
  1625.  
  1626.     return(ch);
  1627. }
  1628.  
  1629.  
  1630.  
  1631.  
  1632. /*
  1633.  *
  1634.  */
  1635. static struct display_line {
  1636.     int   row, col;            /* where display starts         */
  1637.     int   dlen;                /* length of display line     */
  1638.     char *dl;                /* line on display         */
  1639.     char *vl;                /* virtual line          */
  1640.     int   vlen;                /* length of virtual line        */
  1641.     int   vused;            /* length of virtual line in use */
  1642.     int   vbase;            /* first virtual char on display */
  1643. } dline;
  1644.  
  1645.  
  1646.  
  1647. static struct key oe_keys[] =
  1648.        {{"^G","Help",KS_SCREENHELP},    {"^C","Cancel",KS_NONE},
  1649.     {"^T","xxx",KS_NONE},        {"Ret","Accept",KS_NONE},
  1650.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  1651.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  1652.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  1653.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE}};
  1654. static struct key_menu oe_keymenu =
  1655.     {sizeof(oe_keys)/(sizeof(oe_keys[0])*12), 0, 0,0,0,0, oe_keys};
  1656. #define    OE_HELP_KEY    0
  1657. #define    OE_CANCEL_KEY    1
  1658. #define    OE_CTRL_T_KEY    2
  1659. #define    OE_ENTER_KEY    3
  1660.  
  1661.  
  1662. /*---------------------------------------------------------------------- 
  1663.        Prompt user for a string in status line with various options
  1664.  
  1665.   Args: string -- the buffer result is returned in, and original string (if 
  1666.                    any) is passed in.
  1667.         y_base -- y position on screen to start on. 0,0 is upper left
  1668.                     negative numbers start from bottom
  1669.         x_base -- column position on screen to start on. 0,0 is upper left
  1670.         field_len -- Maximum length of string to accept
  1671.         append_current -- flag indicating string should not be truncated before
  1672.                           accepting input
  1673.         passwd -- a pass word is being fetch. Don't echo on screen
  1674.         prompt -- The string to prompt with
  1675.     escape_list -- pointer to array of ESCKEY_S's.  input chars matching
  1676.                        those in list return value from list.
  1677.         help   -- Arrary of strings for help text in bottom screen lines
  1678.         flags  -- flags
  1679.  
  1680.   Result:  editing input string
  1681.             returns -1 unexpected errors
  1682.             returns 0  normal entry typed (editing and return or PF2)
  1683.             returns 1  typed ^C or PF2 (cancel)
  1684.             returns 3  typed ^G or PF1 (help)
  1685.             returns 4  typed ^L for a screen redraw
  1686.  
  1687.   WARNING: Care is required with regard to the escape_list processing.
  1688.            The passed array is terminated with an entry that has ch = -1.
  1689.            Function key labels and key strokes need to be setup externally!
  1690.        Traditionally, a return value of 2 is used for ^T escapes.
  1691.  
  1692.    Unless in escape_list, tabs are trapped by isprint().
  1693. This allows near full weemacs style editing in the line
  1694.    ^A beginning of line
  1695.    ^E End of line
  1696.    ^R Redraw line
  1697.    ^G Help
  1698.    ^F forward
  1699.    ^B backward
  1700.    ^D delete
  1701. ----------------------------------------------------------------------*/
  1702.  
  1703. optionally_enter(string, y_base, x_base, field_len, append_current, passwd,
  1704.                  prompt, escape_list, help, flags)
  1705.      char       *string, *prompt;
  1706.      ESCKEY_S   *escape_list;
  1707.      HelpType     help;
  1708.      int         x_base, y_base, field_len, append_current, passwd;
  1709.      unsigned     flags;
  1710. {
  1711.     register char *s2;
  1712.     register int   field_pos;
  1713.     int            i, j, return_v, cols, ch, prompt_len, too_thin,
  1714.                    real_y_base, cursor_moved, km_popped;
  1715.     char          *saved_original = NULL, *k, *kb;
  1716.     char          *kill_buffer = NULL;
  1717.     char         **help_text;
  1718.     int           fkey_table[12];
  1719.     struct       key_menu *km;
  1720.     bitmap_t       bitmap;
  1721.  
  1722.     dprint(5, (debugfile, "=== optionally_enter called ===\n"));
  1723.     dprint(9, (debugfile, "string:\"%s\"  y:%d  x:%d  length: %d append: %d\n",
  1724.                string, x_base, y_base, field_len, append_current));
  1725.     dprint(9, (debugfile, "passwd:%d   prompt:\"%s\"   label:\"%s\"\n",
  1726.                passwd, prompt, (escape_list && escape_list[0].ch != -1)
  1727.                  ? escape_list[0].label: ""));
  1728.  
  1729. #ifdef _WINDOWS
  1730.     if (mswin_usedialog ()) {
  1731.     MDlgButton        button_list[12];
  1732.     int            b;
  1733.     int            i;
  1734.  
  1735.     memset (&button_list, 0, sizeof (MDlgButton) * 12);
  1736.     b = 0;
  1737.     for (i = 0; escape_list && escape_list[i].ch != -1 && i < 11; ++i) {
  1738.         if (escape_list[i].name != NULL
  1739.         && escape_list[i].ch > 0 && escape_list[i].ch < 256) {
  1740.         button_list[b].ch = escape_list[i].ch;
  1741.         button_list[b].rval = escape_list[i].rval;
  1742.         button_list[b].name = escape_list[i].name;
  1743.         button_list[b].label = escape_list[i].label;
  1744.         ++b;
  1745.         }
  1746.     }
  1747.     button_list[b].ch = -1;
  1748.  
  1749.  
  1750.     help_text = get_help_text (help, NULL);
  1751.     return_v = mswin_dialog (prompt, string, field_len, 
  1752.             append_current, passwd, button_list, help_text, flags);
  1753.     if (help_text != NULL) 
  1754.         free_help_text (help_text);
  1755.         return (return_v);
  1756.     }
  1757. #endif
  1758.  
  1759.     suspend_busy_alarm();
  1760.     cols       = ps_global->ttyo->screen_cols;
  1761.     prompt_len = strlen(prompt);
  1762.     too_thin   = 0;
  1763.     km_popped  = 0;
  1764.     if(y_base > 0) {
  1765.         real_y_base = y_base;
  1766.     } else {
  1767.         real_y_base=  y_base + ps_global->ttyo->screen_rows;
  1768.         if(real_y_base < 2)
  1769.           real_y_base = ps_global->ttyo->screen_rows;
  1770.     }
  1771.  
  1772.     flush_ordered_messages();
  1773.     mark_status_dirty();
  1774.     if(append_current)            /* save a copy in case of cancel */
  1775.       saved_original = cpystr(string);
  1776.  
  1777.     /*
  1778.      * build the function key mapping table, skipping predefined keys...
  1779.      */
  1780.     memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(int));
  1781.     for(i = 0, j = 0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){
  1782.     if(i+j == OE_HELP_KEY)
  1783.       j++;
  1784.  
  1785.     if(i+j == OE_CANCEL_KEY)
  1786.       j++;
  1787.  
  1788.     if(i+j == OE_ENTER_KEY)
  1789.       j++;
  1790.  
  1791.     fkey_table[i+j] = escape_list[i].ch;
  1792.     }
  1793.  
  1794. #if defined(HELPFILE)
  1795.     help_text = (help != NO_HELP) ? get_help_text(help, NULL) : (char **)NULL;
  1796. #else
  1797.     help_text = help;
  1798. #endif
  1799.     if(help_text){            /*---- Show help text -----*/
  1800.     int width = ps_global->ttyo->screen_cols - x_base;
  1801.  
  1802.     if(FOOTER_ROWS(ps_global) == 1){
  1803.         km_popped++;
  1804.         FOOTER_ROWS(ps_global) = 3;
  1805.         clearfooter(ps_global);
  1806.  
  1807.         y_base = -3;
  1808.         real_y_base = y_base + ps_global->ttyo->screen_rows;
  1809.     }
  1810.  
  1811.     for(j = 0; j < 2 && help_text[j]; j++){
  1812.         MoveCursor(real_y_base + 1 + j, x_base);
  1813.         CleartoEOLN();
  1814.  
  1815.         if(width < strlen(help_text[j])){
  1816.         char *tmp = fs_get((width + 1) * sizeof(char));
  1817.         strncpy(tmp, help_text[j], width);
  1818.         tmp[width] = '\0';
  1819.         PutLine0(real_y_base + 1 + j, x_base, tmp);
  1820.         fs_give((void **)&tmp);
  1821.         }
  1822.         else
  1823.           PutLine0(real_y_base + 1 + j, x_base, help_text[j]);
  1824.     }
  1825.  
  1826. #if defined(HELPFILE)
  1827.     free_help_text(help_text);
  1828. #endif
  1829.  
  1830.     } else {
  1831.     clrbitmap(bitmap);
  1832.     clrbitmap((km = &oe_keymenu)->bitmap);        /* force formatting */
  1833.     setbitn(OE_HELP_KEY, bitmap);
  1834.     setbitn(OE_ENTER_KEY, bitmap);
  1835.         if(!(flags & OE_DISALLOW_CANCEL))
  1836.         setbitn(OE_CANCEL_KEY, bitmap);
  1837.     setbitn(OE_CTRL_T_KEY, bitmap);
  1838.  
  1839.         /*---- Show the usual possible keys ----*/
  1840.     for(i=0,j=0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){
  1841.         if(i+j == OE_HELP_KEY)
  1842.           j++;
  1843.  
  1844.         if(i+j == OE_CANCEL_KEY)
  1845.           j++;
  1846.  
  1847.         if(i+j == OE_ENTER_KEY)
  1848.           j++;
  1849.  
  1850.         oe_keymenu.keys[i+j].label = escape_list[i].label;
  1851.         oe_keymenu.keys[i+j].name = escape_list[i].name;
  1852.         setbitn(i+j, bitmap);
  1853.     }
  1854.  
  1855.     for(i = i+j; i < 12; i++)
  1856.       if(!(i == OE_HELP_KEY || i == OE_ENTER_KEY || i == OE_CANCEL_KEY))
  1857.         oe_keymenu.keys[i].name = NULL;
  1858.  
  1859.     draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global),
  1860.         0, FirstMenu, 0);
  1861.     }
  1862.     
  1863.     
  1864.     StartInverse();  /* Always in inverse  */
  1865.  
  1866.     /*
  1867.      * if display length isn't wide enough to support input,
  1868.      * shorten up the prompt...
  1869.      */
  1870.     if((dline.dlen = cols - (x_base + prompt_len + 1)) < 5){
  1871.     prompt_len += (dline.dlen - 5);    /* adding negative numbers */
  1872.     prompt     -= (dline.dlen - 5);    /* subtracting negative numbers */
  1873.     dline.dlen  = 5;
  1874.     }
  1875.  
  1876.     dline.dl    = fs_get((size_t)dline.dlen + 1);
  1877.     memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1) * sizeof(char));
  1878.     dline.row   = real_y_base;
  1879.     dline.col   = x_base + prompt_len;
  1880.     dline.vl    = string;
  1881.     dline.vlen  = --field_len;        /* -1 for terminating NULL */
  1882.     dline.vbase = field_pos = 0;
  1883.  
  1884.     PutLine0(real_y_base, x_base, prompt);
  1885.     /* make sure passed in string is shorter than field_len */
  1886.     /* and adjust field_pos..                               */
  1887.  
  1888.     while(append_current && field_pos < field_len && string[field_pos] != '\0')
  1889.       field_pos++;
  1890.  
  1891.     string[field_pos] = '\0';
  1892.     dline.vused = (int)(&string[field_pos] - string);
  1893.     line_paint(field_pos, &passwd);
  1894.  
  1895. #ifdef    _WINDOWS
  1896.     mswin_allowpaste(MSWIN_PASTE_LINE);
  1897. #endif
  1898.  
  1899.     /*----------------------------------------------------------------------
  1900.       The main loop
  1901.    
  1902.     here field_pos is the position in the string.
  1903.     s always points to where we are in the string.
  1904.     loops until someone sets the return_v.
  1905.       ----------------------------------------------------------------------*/
  1906.     return_v = -10;
  1907.  
  1908.     while(return_v == -10) {
  1909.     /* Timeout 5 min to keep imap mail stream alive */
  1910.         ch = read_char(600);
  1911.  
  1912.     /*
  1913.      * Don't want to intercept all characters if typing in passwd.
  1914.      * We select an ad hoc set that we will catch and let the rest
  1915.      * through.  We would have caught the set below in the big switch
  1916.      * but we skip the switch instead.  Still catch things like ^K,
  1917.      * DELETE, ^C, RETURN.
  1918.      */
  1919.     if(passwd)
  1920.       switch(ch) {
  1921.             case ctrl('F'):  
  1922.         case KEY_RIGHT:
  1923.             case ctrl('B'):
  1924.         case KEY_LEFT:
  1925.             case ctrl('U'):
  1926.             case ctrl('A'):
  1927.         case KEY_HOME:
  1928.             case ctrl('E'):
  1929.         case KEY_END:
  1930.         case TAB:
  1931.           goto ok_for_passwd;
  1932.       }
  1933.  
  1934.         if(too_thin && ch != KEY_RESIZE && ch != ctrl('Z'))
  1935.           goto bleep;
  1936.  
  1937.     switch(ch) {
  1938.  
  1939.         /*--------------- KEY RIGHT ---------------*/
  1940.           case ctrl('F'):  
  1941.       case KEY_RIGHT:
  1942.         if(field_pos >= field_len || string[field_pos] == '\0')
  1943.               goto bleep;
  1944.  
  1945.         line_paint(++field_pos, &passwd);
  1946.         break;
  1947.  
  1948.         /*--------------- KEY LEFT ---------------*/
  1949.           case ctrl('B'):
  1950.       case KEY_LEFT:
  1951.         if(field_pos <= 0)
  1952.           goto bleep;
  1953.  
  1954.         line_paint(--field_pos, &passwd);
  1955.         break;
  1956.  
  1957.           /*-------------------- WORD SKIP --------------------*/
  1958.       case ctrl('@'):
  1959.         /*
  1960.          * Note: read_char *can* return NO_OP_COMMAND which is
  1961.          * the def'd with the same value as ^@ (NULL), BUT since
  1962.          * read_char has a big timeout (>25 secs) it won't.
  1963.          */
  1964.  
  1965.         /* skip thru current word */
  1966.         while(string[field_pos]
  1967.           && isalnum((unsigned char) string[field_pos]))
  1968.           field_pos++;
  1969.  
  1970.         /* skip thru current white space to next word */
  1971.         while(string[field_pos]
  1972.           && !isalnum((unsigned char) string[field_pos]))
  1973.           field_pos++;
  1974.  
  1975.         line_paint(field_pos, &passwd);
  1976.         break;
  1977.  
  1978.           /*--------------------  RETURN --------------------*/
  1979.       case PF4:
  1980.         if(F_OFF(F_USE_FK,ps_global)) goto bleep;
  1981.       case ctrl('J'): 
  1982.       case ctrl('M'): 
  1983.         return_v = 0;
  1984.         break;
  1985.  
  1986.           /*-------------------- Destructive backspace --------------------*/
  1987.       case '\177': /* DEL */
  1988.       case ctrl('H'):
  1989.             /*   Try and do this with by telling the terminal to delete a
  1990.                  a character. If that fails, then repaint the rest of the
  1991.                  line, acheiving the same much less efficiently
  1992.              */
  1993.         if(field_pos <= 0) goto bleep;
  1994.         field_pos--;
  1995.         /* drop thru to pull line back ... */
  1996.  
  1997.           /*-------------------- Delete char --------------------*/
  1998.       case ctrl('D'): 
  1999.       case KEY_DEL: 
  2000.             if(field_pos >= field_len || !string[field_pos]) goto bleep;
  2001.  
  2002.         dline.vused--;
  2003.         for(s2 = &string[field_pos]; *s2 != '\0'; s2++)
  2004.           *s2 = s2[1];
  2005.  
  2006.         *s2 = '\0';            /* Copy last NULL */
  2007.         line_paint(field_pos, &passwd);
  2008.         break;
  2009.  
  2010.  
  2011.             /*--------------- Kill line -----------------*/
  2012.           case ctrl('K'):
  2013.             if(kill_buffer != NULL)
  2014.               fs_give((void **)&kill_buffer);
  2015.  
  2016.         if(field_pos != 0 || string[0]){
  2017.         if(!passwd && F_ON(F_DEL_FROM_DOT, ps_global))
  2018.           dline.vused -= strlen(&string[i = field_pos]);
  2019.         else
  2020.           dline.vused = i = 0;
  2021.  
  2022.         kill_buffer = cpystr(&string[field_pos = i]);
  2023.         string[field_pos] = '\0';
  2024.         line_paint(field_pos, &passwd);
  2025.         }
  2026.  
  2027.             break;
  2028.  
  2029.             /*------------------- Undelete line --------------------*/
  2030.           case ctrl('U'):
  2031.             if(kill_buffer == NULL)
  2032.               goto bleep;
  2033.  
  2034.             /* Make string so it will fit */
  2035.             kb = cpystr(kill_buffer);
  2036.             dprint(2, (debugfile,
  2037.                "Undelete: %d %d\n", strlen(string), field_len));
  2038.             if(strlen(kb) + strlen(string) > field_len) 
  2039.                 kb[field_len - strlen(string)] = '\0';
  2040.             dprint(2, (debugfile,
  2041.                "Undelete: %d %d\n", field_len - strlen(string),
  2042.                strlen(kb)));
  2043.                        
  2044.             if(string[field_pos] == '\0') {
  2045.                 /*--- adding to the end of the string ----*/
  2046.                 for(k = kb; *k; k++)
  2047.           string[field_pos++] = *k;
  2048.  
  2049.                 string[field_pos] = '\0';
  2050.             } else {
  2051.                 goto bleep;
  2052.                 /* To lazy to do insert in middle of string now */
  2053.             }
  2054.  
  2055.         dline.vused = strlen(string);
  2056.             fs_give((void **)&kb);
  2057.         line_paint(field_pos, &passwd);
  2058.             break;
  2059.             
  2060.  
  2061.         /*-------------------- Interrupt --------------------*/
  2062.       case ctrl('C'): /* ^C */ 
  2063.         if(F_ON(F_USE_FK,ps_global) || flags & OE_DISALLOW_CANCEL)
  2064.           goto bleep;
  2065.  
  2066.         goto cancel;
  2067.       case PF2:
  2068.         if(F_OFF(F_USE_FK,ps_global) || flags & OE_DISALLOW_CANCEL)
  2069.           goto bleep;
  2070.  
  2071.       cancel:
  2072.         return_v = 1;
  2073.         if(saved_original)
  2074.           strcpy(string, saved_original);
  2075.  
  2076.         break;
  2077.         
  2078.  
  2079.           case ctrl('A'):
  2080.       case KEY_HOME:
  2081.             /*-------------------- Start of line -------------*/
  2082.         line_paint(field_pos = 0, &passwd);
  2083.             break;
  2084.  
  2085.  
  2086.           case ctrl('E'):
  2087.       case KEY_END:
  2088.             /*-------------------- End of line ---------------*/
  2089.         line_paint(field_pos = dline.vused, &passwd);
  2090.             break;
  2091.  
  2092.  
  2093.         /*-------------------- Help --------------------*/
  2094.       case ctrl('G') : 
  2095.       case PF1:
  2096.         if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){
  2097.         km_popped++;
  2098.         FOOTER_ROWS(ps_global) = 3;
  2099.         clearfooter(ps_global);
  2100.         EndInverse();
  2101.         draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global),
  2102.             0, FirstMenu, 0);
  2103.         StartInverse();
  2104.         mark_keymenu_dirty();
  2105.         y_base = -3;
  2106.         dline.row = real_y_base = y_base + ps_global->ttyo->screen_rows;
  2107.         PutLine0(real_y_base, x_base, prompt);
  2108.         fs_resize((void **)&dline.dl, (size_t)dline.dlen + 1);
  2109.         memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1));
  2110.         line_paint(field_pos, &passwd);
  2111.         break;
  2112.         }
  2113.  
  2114.         if(FOOTER_ROWS(ps_global) > 1){
  2115.         mark_keymenu_dirty();
  2116.         return_v = 3;
  2117.         }
  2118.         else
  2119.           goto bleep;
  2120.  
  2121.         break;
  2122.  
  2123.           case NO_OP_IDLE:
  2124.             if(new_mail(0, 2, 0) < 0)    /* Keep mail stream alive */
  2125.               break;            /* no changes, get on with life */
  2126.             /* Else fall into redraw */
  2127.  
  2128.         /*-------------------- Redraw --------------------*/
  2129.       case ctrl('L'):
  2130.             /*---------------- re size ----------------*/
  2131.           case KEY_RESIZE:
  2132.             
  2133.         dline.row = real_y_base = y_base > 0 ? y_base :
  2134.                      y_base + ps_global->ttyo->screen_rows;
  2135.             EndInverse();
  2136.             ClearScreen();
  2137.             redraw_titlebar();
  2138.             if(ps_global->redrawer != (void (*)())NULL)
  2139.               (*ps_global->redrawer)();
  2140.  
  2141.             redraw_keymenu();
  2142.             StartInverse();
  2143.             
  2144.             PutLine0(real_y_base, x_base, prompt);
  2145.             cols     =  ps_global->ttyo->screen_cols;
  2146.             too_thin = 0;
  2147.             if(cols < x_base + prompt_len + 4) {
  2148.         Writechar(BELL, 0);
  2149.                 PutLine0(real_y_base, 0, "Screen's too thin. Ouch!");
  2150.                 too_thin = 1;
  2151.             } else {
  2152.         dline.col   = x_base + prompt_len;
  2153.         dline.dlen  = cols - (x_base + prompt_len + 1);
  2154.         fs_resize((void **)&dline.dl, (size_t)dline.dlen + 1);
  2155.         memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1));
  2156.         line_paint(field_pos, &passwd);
  2157.             }
  2158.             fflush(stdout);
  2159.  
  2160.             dprint(9, (debugfile,
  2161.                     "optionally_enter  RESIZE new_cols:%d  too_thin: %d\n",
  2162.                        cols, too_thin));
  2163.             break;
  2164.  
  2165.       case PF3 :        /* input to potentially remap */
  2166.       case PF5 :
  2167.       case PF6 :
  2168.       case PF7 :
  2169.       case PF8 :
  2170.       case PF9 :
  2171.       case PF10 :
  2172.       case PF11 :
  2173.       case PF12 :
  2174.           if(F_ON(F_USE_FK,ps_global)
  2175.          && fkey_table[ch - PF1] != NO_OP_COMMAND)
  2176.         ch = fkey_table[ch - PF1]; /* remap function key input */
  2177.   
  2178.           default:
  2179.         if(escape_list){        /* in the escape key list? */
  2180.         for(j=0; escape_list[j].ch != -1; j++){
  2181.             if(escape_list[j].ch == ch){
  2182.             return_v = escape_list[j].rval;
  2183.             break;
  2184.             }
  2185.         }
  2186.  
  2187.         if(return_v != -10)
  2188.           break;
  2189.         }
  2190.  
  2191.         if(iscntrl(ch & 0x7f)){
  2192.        bleep:
  2193.         putc(BELL, stdout);
  2194.         continue;
  2195.         }
  2196.  
  2197.        ok_for_passwd:
  2198.         /*--- Insert a character -----*/
  2199.         if(dline.vused >= field_len)
  2200.           goto bleep;
  2201.  
  2202.         /*---- extending the length of the string ---*/
  2203.         for(s2 = &string[++dline.vused]; s2 - string > field_pos; s2--)
  2204.           *s2 = *(s2-1);
  2205.  
  2206.         string[field_pos++] = ch;
  2207.         line_paint(field_pos, &passwd);
  2208.             
  2209.     }   /*---- End of switch on char ----*/
  2210.     }
  2211.  
  2212. #ifdef    _WINDOWS
  2213.     mswin_allowpaste(MSWIN_PASTE_DISABLE);
  2214. #endif
  2215.     fs_give((void **)&dline.dl);
  2216.     if(saved_original) 
  2217.       fs_give((void **)&saved_original);
  2218.  
  2219.     if(kill_buffer)
  2220.       fs_give((void **)&kill_buffer);
  2221.  
  2222.     removing_trailing_white_space(string);
  2223.     EndInverse();
  2224.     MoveCursor(real_y_base, x_base); /* Move the cursor to show we're done */
  2225.     fflush(stdout);
  2226.     resume_busy_alarm();
  2227.     if(km_popped){
  2228.     FOOTER_ROWS(ps_global) = 1;
  2229.     clearfooter(ps_global);
  2230.     ps_global->mangled_body = 1;
  2231.     }
  2232.  
  2233.     return(return_v);
  2234. }
  2235.  
  2236.  
  2237. /*
  2238.  * line_paint - where the real work of managing what is displayed gets done.
  2239.  *              The passwd variable is overloaded: if non-zero, don't
  2240.  *              output anything, else only blat blank chars across line
  2241.  *              once and use this var to tell us we've already written the 
  2242.  *              line.
  2243.  */
  2244. void
  2245. line_paint(offset, passwd)
  2246.     int   offset;            /* current dot offset into line */
  2247.     int  *passwd;            /* flag to hide display of chars */
  2248. {
  2249.     register char *pfp, *pbp;
  2250.     register char *vfp, *vbp;
  2251.     int            extra = 0;
  2252. #define DLEN    (dline.vbase + dline.dlen)
  2253.  
  2254.     /*
  2255.      * for now just leave line blank, but maybe do '*' for each char later
  2256.      */
  2257.     if(*passwd){
  2258.     if(*passwd > 1)
  2259.       return;
  2260.     else
  2261.       *passwd == 2;        /* only blat once */
  2262.  
  2263.     extra = 0;
  2264.     MoveCursor(dline.row, dline.col);
  2265.     while(extra++ < dline.dlen)
  2266.       Writechar(' ', 0);
  2267.  
  2268.     MoveCursor(dline.row, dline.col);
  2269.     return;
  2270.     }
  2271.  
  2272.     /* adjust right margin */
  2273.     while(offset >= DLEN + ((dline.vused > DLEN) ? -1 : 1))
  2274.       dline.vbase += dline.dlen/2;
  2275.  
  2276.     /* adjust left margin */
  2277.     while(offset < dline.vbase + ((dline.vbase) ? 2 : 0))
  2278.       dline.vbase = max(dline.vbase - (dline.dlen/2), 0);
  2279.  
  2280.     if(dline.vbase){                /* off screen cue left */
  2281.     vfp = &dline.vl[dline.vbase+1];
  2282.     pfp = &dline.dl[1];
  2283.     if(dline.dl[0] != '<'){
  2284.         MoveCursor(dline.row, dline.col);
  2285.         Writechar(dline.dl[0] = '<', 0);
  2286.     }
  2287.     }
  2288.     else{
  2289.     vfp = dline.vl;
  2290.     pfp = dline.dl;
  2291.     if(dline.dl[0] == '<'){
  2292.         MoveCursor(dline.row, dline.col);
  2293.         Writechar(dline.dl[0] = ' ', 0);
  2294.     }
  2295.     }
  2296.  
  2297.     if(dline.vused > DLEN){            /* off screen right... */
  2298.     vbp = vfp + (long)(dline.dlen-(dline.vbase ? 2 : 1));
  2299.     pbp = pfp + (long)(dline.dlen-(dline.vbase ? 2 : 1));
  2300.     if(pbp[1] != '>'){
  2301.         MoveCursor(dline.row, dline.col+dline.dlen);
  2302.         Writechar(pbp[1] = '>', 0);
  2303.     }
  2304.     }
  2305.     else{
  2306.     extra = dline.dlen - (dline.vused - dline.vbase);
  2307.     vbp = &dline.vl[max(0, dline.vused-1)];
  2308.     pbp = &dline.dl[dline.dlen];
  2309.     if(pbp[0] == '>'){
  2310.         MoveCursor(dline.row, dline.col+dline.dlen);
  2311.         Writechar(pbp[0] = ' ', 0);
  2312.     }
  2313.     }
  2314.  
  2315.     while(*pfp == *vfp && vfp < vbp)            /* skip like chars */
  2316.       pfp++, vfp++;
  2317.  
  2318.     if(pfp == pbp && *pfp == *vfp){            /* nothing to paint! */
  2319.     MoveCursor(dline.row, dline.col + (offset - dline.vbase));
  2320.     return;
  2321.     }
  2322.  
  2323.     /* move backward thru like characters */
  2324.     if(extra){
  2325.     while(extra >= 0 && *pbp == ' ')         /* back over spaces */
  2326.       extra--, pbp--;
  2327.  
  2328.     while(extra >= 0)                /* paint new ones    */
  2329.       pbp[-(extra--)] = ' ';
  2330.     }
  2331.  
  2332.     if((vbp - vfp) == (pbp - pfp)){            /* space there? */
  2333.     while((*pbp == *vbp) && pbp != pfp)        /* skip like chars */
  2334.       pbp--, vbp--;
  2335.     }
  2336.  
  2337.     if(pfp != pbp || *pfp != *vfp){            /* anything to paint?*/
  2338.     MoveCursor(dline.row, dline.col + (int)(pfp - dline.dl));
  2339.  
  2340.     do
  2341.       Writechar((unsigned char)((vfp <= vbp && *vfp)
  2342.               ? ((*pfp = *vfp++) == TAB) ? ' ' : *pfp
  2343.               : (*pfp = ' ')), 0);
  2344.     while(++pfp <= pbp);
  2345.     }
  2346.  
  2347.     MoveCursor(dline.row, dline.col + (offset - dline.vbase));
  2348. }
  2349.  
  2350.  
  2351.  
  2352. /*----------------------------------------------------------------------
  2353.     Check to see if the given command is reasonably valid
  2354.   
  2355.   Args:  ch -- the character to check
  2356.  
  2357.  Result:  A valid command is returned, or a well know bad command is returned.
  2358.  
  2359.  ---*/
  2360. validatekeys(ch)
  2361.      int  ch;
  2362. {
  2363. #ifndef _WINDOWS
  2364.     if(F_ON(F_USE_FK,ps_global)) {
  2365.     if(ch >= 'a' && ch <= 'z')
  2366.       return(KEY_JUNK);
  2367.     } else {
  2368.     if(ch >= PF1 && ch <= PF12)
  2369.       return(KEY_JUNK);
  2370.     }
  2371. #else
  2372.     /*
  2373.      * In windows menu items are bound to a single key command which
  2374.      * gets inserted into the input stream as if the user had typed
  2375.      * that key.  But all the menues are bonund to alphakey commands,
  2376.      * not PFkeys.  to distinguish between a keyboard command and a
  2377.      * menu command we insert a flag (KEY_MENU_FLAG) into the
  2378.      * command value when setting up the bindings in
  2379.      * configure_menu_items().  Here we strip that flag.
  2380.      */
  2381.     if(F_ON(F_USE_FK,ps_global)) {
  2382.     if(ch >= 'a' && ch <= 'z' && !(ch & KEY_MENU_FLAG))
  2383.       return(KEY_JUNK);
  2384.     ch &= ~ KEY_MENU_FLAG;
  2385.     } else {
  2386.     ch &= ~ KEY_MENU_FLAG;
  2387.     if(ch >= PF1 && ch <= PF12)
  2388.       return(KEY_JUNK);
  2389.     }
  2390. #endif
  2391.  
  2392.     return(ch);
  2393. }
  2394.  
  2395.  
  2396.  
  2397. /*----------------------------------------------------------------------
  2398.   Prepend config'd commands to keyboard input
  2399.   
  2400.   Args:  ch -- pointer to storage for returned command
  2401.  
  2402.  Returns: TRUE if we're passing back a useful command, FALSE otherwise
  2403.  
  2404.  ---*/
  2405. int
  2406. process_config_input(ch)
  2407.     int *ch;
  2408. {
  2409.     static char firsttime = (char) 1;
  2410.  
  2411.     /* commands in config file */
  2412.     if(ps_global->initial_cmds && *ps_global->initial_cmds) {
  2413.     /*
  2414.      * There are a few commands that may require keyboard input before
  2415.      * we enter the main command loop.  That input should be interactive,
  2416.      * not from our list of initial keystrokes.
  2417.      */
  2418.     if(ps_global->dont_use_init_cmds)
  2419.       return(0);
  2420.  
  2421.     *ch = *ps_global->initial_cmds++;
  2422.     if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
  2423.         fs_give((void **)&(ps_global->free_initial_cmds));
  2424.         ps_global->initial_cmds = 0;
  2425.     }
  2426.  
  2427.     return(1);
  2428.     }
  2429.  
  2430.     if(firsttime) {
  2431.     firsttime = 0;
  2432.     if(ps_global->in_init_seq) {
  2433.         ps_global->in_init_seq = 0;
  2434.         ps_global->save_in_init_seq = 0;
  2435.         clear_cursor_pos();
  2436.         F_SET(F_USE_FK,ps_global,ps_global->orig_use_fkeys);
  2437.         /* draw screen */
  2438.         *ch = ctrl('L');
  2439.         return(1);
  2440.     }
  2441.     }
  2442.  
  2443.     return(0);
  2444. }
  2445.  
  2446.  
  2447.  
  2448. /*----------------------------------------------------------------------
  2449.     record and playback user keystrokes
  2450.   
  2451.   Args:  ch -- the character to record
  2452.      play -- flag to tell us to return first recorded char on tape
  2453.  
  2454.  Returns: either character recorded or played back or -1 to indicate
  2455.       end of recording
  2456.  
  2457.  ---*/
  2458. #define    TAPELEN    256
  2459.  
  2460. int
  2461. key_recorder(ch, play)
  2462.     int  ch;
  2463.     int  play;
  2464. {
  2465.     static int     tape[TAPELEN];
  2466.     static long  recorded = 0L;
  2467.     static short length  = 0;
  2468.  
  2469.     if(play){
  2470.     ch = length ? tape[(recorded + TAPELEN - length--) % TAPELEN] : -1;
  2471.     }
  2472.     else{
  2473.     tape[recorded++ % TAPELEN] = ch;
  2474.     if(length < TAPELEN)
  2475.       length++;
  2476.     }
  2477.  
  2478.     return(ch);
  2479. }
  2480.